/**
 * 音频录制工具类
 */
export class AudioRecorder {
  constructor() {
    this.mediaRecorder = null
    this.audioChunks = []
    this.isRecording = false
    this.stream = null
  }

  /**
   * 请求麦克风权限并初始化录音器
   */
  async initialize() {
    try {
      // 请求麦克风权限
      this.stream = await navigator.mediaDevices.getUserMedia({
        audio: {
          sampleRate: 16000,
          channelCount: 1,
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true
        }
      })

      // 创建MediaRecorder
      this.mediaRecorder = new MediaRecorder(this.stream, {
        mimeType: 'audio/webm;codecs=opus',
        audioBitsPerSecond: 16000
      })

      // 设置数据收集事件
      this.mediaRecorder.ondataavailable = (event) => {
        if (event.data.size > 0) {
          this.audioChunks.push(event.data)
        }
      }

      return true
    } catch (error) {
      console.error('初始化音频录制失败:', error)
      throw new Error('无法访问麦克风，请检查权限设置')
    }
  }

  /**
   * 开始录音
   */
  startRecording() {
    if (!this.mediaRecorder || this.isRecording) {
      return
    }

    this.audioChunks = []
    this.isRecording = true
    this.mediaRecorder.start(100) // 每100ms收集一次数据
    console.log('开始录音')
  }

  /**
   * 停止录音并返回音频数据
   */
  async stopRecording() {
    if (!this.mediaRecorder || !this.isRecording) {
      return null
    }

    return new Promise((resolve) => {
      this.mediaRecorder.onstop = async () => {
        this.isRecording = false
        
        // 创建Blob
        const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' })
        
        // 转换为WAV格式
        const wavData = await this.convertToWav(audioBlob)
        console.log('录音完成，数据大小:', wavData.byteLength)
        
        resolve(wavData)
      }

      this.mediaRecorder.stop()
    })
  }

  /**
   * 将WebM格式转换为WAV格式
   */
  async convertToWav(audioBlob) {
    try {
      // 使用Web Audio API进行格式转换
      const arrayBuffer = await audioBlob.arrayBuffer()
      const audioContext = new (window.AudioContext || window.webkitAudioContext)()
      const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)
      
      // 转换为16位PCM WAV格式
      return this.audioBufferToWav(audioBuffer)
    } catch (error) {
      console.error('音频格式转换失败:', error)
      // 如果转换失败，返回原始数据
      return await audioBlob.arrayBuffer()
    }
  }

  /**
   * 将AudioBuffer转换为WAV格式
   */
  audioBufferToWav(buffer) {
    const length = buffer.length
    const sampleRate = buffer.sampleRate
    const numberOfChannels = buffer.numberOfChannels
    const bytesPerSample = 2
    const blockAlign = numberOfChannels * bytesPerSample
    const byteRate = sampleRate * blockAlign
    const dataSize = length * blockAlign
    const bufferSize = 44 + dataSize

    const arrayBuffer = new ArrayBuffer(bufferSize)
    const view = new DataView(arrayBuffer)

    // WAV文件头
    const writeString = (offset, string) => {
      for (let i = 0; i < string.length; i++) {
        view.setUint8(offset + i, string.charCodeAt(i))
      }
    }

    writeString(0, 'RIFF')
    view.setUint32(4, bufferSize - 8, true)
    writeString(8, 'WAVE')
    writeString(12, 'fmt ')
    view.setUint32(16, 16, true)
    view.setUint16(20, 1, true)
    view.setUint16(22, numberOfChannels, true)
    view.setUint32(24, sampleRate, true)
    view.setUint32(28, byteRate, true)
    view.setUint16(32, blockAlign, true)
    view.setUint16(34, 16, true)
    writeString(36, 'data')
    view.setUint32(40, dataSize, true)

    // 写入音频数据
    let offset = 44
    for (let i = 0; i < length; i++) {
      for (let channel = 0; channel < numberOfChannels; channel++) {
        const sample = Math.max(-1, Math.min(1, buffer.getChannelData(channel)[i]))
        view.setInt16(offset, sample < 0 ? sample * 0x8000 : sample * 0x7FFF, true)
        offset += 2
      }
    }

    return arrayBuffer
  }

  /**
   * 释放资源
   */
  dispose() {
    if (this.mediaRecorder) {
      this.mediaRecorder = null
    }
    
    if (this.stream) {
      this.stream.getTracks().forEach(track => track.stop())
      this.stream = null
    }
    
    this.audioChunks = []
    this.isRecording = false
  }
}
